package Tests;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

import MailSystem.Connection;
import MailSystem.MailSystem;
import MailSystem.Mailbox;
import MailSystem.Message;
import MailSystem.Telephone;
import MailSystem.TelephoneResources;
import static org.mockito.Mockito.*;

public class ConnectionTest {
	Telephone phoneMock;
	MailSystem mailSystemMock;
	Connection connection;
	Mailbox box = new Mailbox("123", "Hello everybody", "");
	String greeting = "Hola a todos";
	String name = "Pedro";
	
	@Before
	public void doBefore()
	{
		phoneMock = mock(Telephone.class);
		mailSystemMock = mock(MailSystem.class);
		connection = new Connection(mailSystemMock);
		connection.addPhone(phoneMock);
	}

	@Test
	public void testConnection()
	{		
		assertTrue(connection.isConnected());
		verify(phoneMock).speak(TelephoneResources.INITIAL_PROMPT);		
	}
	
	@Test
	public void testConnectAndChangeToRecordingStatus()
	{
		
		findMailBox();
		
		assertTrue(connection.isRecording());
		verify(phoneMock).speak(box.getGreeting());
	}
	
	@Test
	public void testConnectAndDontFindMailBox()
	{
		
		when(mailSystemMock.findMailbox("12")).thenReturn(null);
		connection.dial("1");
		connection.dial("2");
		connection.dial("#");
		
		assertFalse(connection.isRecording());
		verify(phoneMock).speak(TelephoneResources.INCORRECTMAILBOX);		
	}
	
	@Test
	public void testLoginSucessfull()
	{
		
		login();
		assertTrue(connection.isMailBoxMenuStatus());
	}
	
	@Test
	public void testLoginPasswordIncorrect()
	{
		
		findMailBox();
		
		// Login!
		connection.dial("1");
		connection.dial("1");
		connection.dial("2");
		connection.dial("#");
		assertFalse(connection.isMailBoxMenuStatus());
		verify(phoneMock).speak(TelephoneResources.INCORRECTPASSCODE);		
	}
	
	@Test
	public void testGoToMessageMenuStatus()
	{
		
		login();	
		
		// Pass to mailBoxMenu
		connection.dial("1");
		assertTrue(connection.isMessageMenuStatus());
		verify(phoneMock).showDisplay(TelephoneResources.MESSAGE_MENU_TEXT);		
	}
	
	@Test
	public void testGoToChangePassCodeStatus()
	{
		
		login();	
		
		// Pass to Change pass code status
		connection.dial("2");
		assertTrue(connection.isChangePassCodeStatus());
		verify(phoneMock).speak(TelephoneResources.NEWPASSCODE);		
	}
	
	@Test
	public void testGoToChangeGreetingStatus()
	{
		
		login();	
		
		// Pass to Change Greeting status
		connection.dial("3");
		assertTrue(connection.isChangeGreetingStatus());
		verify(phoneMock).speak(TelephoneResources.NEWGREETING);		
	}
	
	@Test
	public void changePassCodeTest()
	{
		
		login();	
		
		// Pass to Change pass code status
		connection.dial("2");
		
		// Change password
		connection.dial("4");
		connection.dial("5");
		connection.dial("6");
		connection.dial("#");
		
		assertTrue(box.checkPasscode("456"));
		assertTrue(connection.isMailBoxMenuStatus());
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MAILBOX_MENU_TEXT);
	}
	
	@Test
	public void changeGreetingTest()
	{
		
		login();		
		
		// Pass to Change Greeting status
		connection.dial("3");
		
		// Change Greeting
		connection.record(greeting);
		connection.dial("#");
		assertEquals(greeting, box.getGreeting());
		assertTrue(connection.isMailBoxMenuStatus());
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MAILBOX_MENU_TEXT);
	}
	
	@Test
	public void changeNameTest()
	{
		
		login();		
		
		// Pass to Change Name status
		connection.dial("4");
		
		// Change Greeting
		connection.record(name);
		connection.dial("#");
		assertEquals(name, box.getName());
		assertTrue(connection.isMailBoxMenuStatus());
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MAILBOX_MENU_TEXT);
	}
	
	@Test
	public void addContactTest()
	{
		login();
		Mailbox box2 = new Mailbox("123", "Hello everybody", "");
		when(mailSystemMock.findMailbox("2")).thenReturn(box2);
		
		// Pass to Change Name status
		connection.dial("5");
		
		connection.dial("2");
		connection.dial("#");
		
		verify(phoneMock).speak(box2.getName() + TelephoneResources.CONTACT_ADDED);
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MAILBOX_MENU_TEXT);
	}
	
	@Test
	public void addContactTestNotFound()
	{
		login();
		when(mailSystemMock.findMailbox("2")).thenReturn(null);
		
		// Pass to Change Name status
		connection.dial("5");
		
		connection.dial("2");
		connection.dial("#");
		
		verify(phoneMock).speak(TelephoneResources.INCORRECTMAILBOX);
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MAILBOX_MENU_TEXT);
	}
	
	@Test
	public void testListenMessageWithASavedMessage()
	{	
		box = new Mailbox("123", "Hello everybody", "");
		String message = "Hola, soy pepito";
		box.addMessage(new Message(message));
		
		passToMailBoxMenu();
		
		// Get message
		connection.dial("1");
		
		verify(phoneMock).speak(message + "\n");
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MESSAGE_MENU_TEXT);
	}
	
	@Test
	public void testListenMessageWithZeroMessages()
	{
		
		passToMailBoxMenu();
		
		// Get message
		connection.dial("1");
		
		verify(phoneMock).speak(TelephoneResources.NOMESSAGE);
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MESSAGE_MENU_TEXT);
	}
	
	@Test
	public void testSaveMessage()
	{
		
		box = new Mailbox("123", "Hello everybody", "");
		String message = "Hola, soy pepito";
		
		box.addMessage(new Message(message));
		box.addMessage(new Message("Hola"));
		
		passToMailBoxMenu();
		
		// Save message
		connection.dial("2");
		
		box.removeCurrentMessage();
		assertEquals(message, box.getCurrentMessage().getText());
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MESSAGE_MENU_TEXT);
	}
	
	@Test
	public void testRemoveCurrentMessage()
	{
		box = new Mailbox("123", "Hello everybody", "");
		String message = "Hola, soy pepito";
		
		box.addMessage(new Message("Hola"));
		box.addMessage(new Message(message));
		
		passToMailBoxMenu();
		
		// Remove message
		connection.dial("3");
		
		assertEquals(message, box.getCurrentMessage().getText());
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MESSAGE_MENU_TEXT);
	}
	
	@Test
	public void testBroadcastCurrenttMessage()
	{
		box = new Mailbox("123", "Hello everybody", "");
		String message = "Hola, soy pepito";
		
		box.addMessage(new Message("Hola"));
		box.addMessage(new Message(message));
		
		passToMailBoxMenu();
		
		connection.dial("4");
		
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MESSAGE_MENU_TEXT);
	}
	
	@Test
	public void testResendCurrentMessage()
	{
		box = new Mailbox("123", "Hello everybody", "");
		Mailbox box2 = new Mailbox("123", "Hello everybody", "");
		String message = "Hola, soy pepito";
				
		box.addMessage(new Message(message));		
		box.addContact("123", box2);
		
		passToMailBoxMenu();
		
		connection.dial("5");
		
		connection.dial("1");
		connection.dial("2");
		connection.dial("3");
		connection.dial("#");		
				
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MESSAGE_MENU_TEXT);
		assertEquals(message, box2.getCurrentMessage().getText());
	}
	
	@Test
	public void returnToMailBoxMenuFromMessageMenu()
	{
		box = new Mailbox("123", "Hello everybody", "");
		String message = "Hola, soy pepito";
		
		box.addMessage(new Message("Hola"));
		box.addMessage(new Message(message));
		
		passToMailBoxMenu();
		
		// Return to MailBoxMenu
		connection.dial("6");
		assertTrue(connection.isMailBoxMenuStatus());
		verify(phoneMock).showDisplay(TelephoneResources.MESSAGE_MENU_TEXT);
		verify(phoneMock, atLeast(2)).showDisplay(TelephoneResources.MAILBOX_MENU_TEXT);
	}
	
	@Test
	public void hangupTest()
	{
		
		findMailBox();		
		connection.hangup();
		assertEquals("", box.getCurrentMessage().getText());
	}
	
	@Test
	public void whenCreateConnectionWeHaveZeroPhones()
	{
		connection = new Connection(mailSystemMock);
		
		assertEquals(0,connection.getPhonesCount());
	}
	
	@Test
	public void addPhoneTest()
	{
		connection = new Connection(mailSystemMock);
		
		connection.addPhone(phoneMock);
		assertEquals(1,connection.getPhonesCount());
	}
	
	public void findMailBox()
	{
		// First find the mailbox
		when(mailSystemMock.findMailbox("12")).thenReturn(box);
		connection.dial("1");
		connection.dial("2");
		connection.dial("#");
	}
	
	public void login()
	{
		findMailBox();
		
		connection.dial("1");
		connection.dial("2");
		connection.dial("3");
		connection.dial("#");
	}
	
	public void passToMailBoxMenu()
	{
		login();
		// Pass to mailBoxMenu
		connection.dial("1");
	}
}
